package com.tianji.learning.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.api.dto.leanring.LearningRecordDTO;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.constants.MqConstants;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningRecordFormDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.SectionType;
import com.tianji.learning.listeners.message.SignInMessage;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.utils.LearningRecordDelayTaskHandler;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

import static com.tianji.common.constants.MqConstants.Exchange.LEARNING_EXCHANGE;
import static com.tianji.common.constants.MqConstants.Key.LEARN_SECTION;

/**
 * <p>
 * 学习记录表 服务实现类
 * </p>
 *
 * @author rui
 * @since 2024-07-16
 */
@Service
@RequiredArgsConstructor
public class LearningRecordServiceImpl extends ServiceImpl<LearningRecordMapper, LearningRecord> implements ILearningRecordService {
    private final ILearningLessonService learningLessonService;
    private final CourseClient courseClient;
    private final LearningRecordDelayTaskHandler recordDelayTaskHandler;
    private final RabbitMqHelper mqHelper;
    @Override
    public LearningLessonDTO queryLearningRecordByCourse(Long courseId) {
        //1.获取用户id
        Long userId = UserContext.getUser();
        //2.查询课表数据
        LearningLesson learningLesson = learningLessonService.lambdaQuery()
                .eq(LearningLesson::getCourseId, courseId)
                .eq(LearningLesson::getUserId, userId)
                .one();
        if(learningLesson == null){
            throw new DbException("课表数据不存在");
        }
        //3.封装返回结果
        LearningLessonDTO lessonDTO = new LearningLessonDTO();
        lessonDTO.setId(learningLesson.getId());
        lessonDTO.setLatestSectionId(learningLesson.getLatestSectionId());
        List<LearningRecord> recordList = this.lambdaQuery()
                .eq(LearningRecord::getLessonId, learningLesson.getId())
                .eq(LearningRecord::getUserId, userId)
                .list();
        lessonDTO.setRecords(BeanUtil.copyToList(recordList,LearningRecordDTO.class));
        return lessonDTO;
    }

    @Override
    public void addLearningRecord(LearningRecordFormDTO formDTO) {
        //1.获取当前用户信息
        Long userId = UserContext.getUser();
        //2.处理学习记录
        //2.1 判断小节类型
        boolean isFinished; //判断是否是第一次完成
        if(formDTO.getSectionType() == SectionType.VIDEO){
            //类型为视频,注意此接口会频繁被前端请求，所以判断是否是第一次完成可以在存在学习记录之后
            isFinished = handleVideoRecord(userId,formDTO);
        }
        else{
            //类型为考试
            isFinished = handleExamRecord(userId,formDTO);
        }
        //3.处理课表记录
        //判断是否第一次学完，处理课表数据
        LearningLesson learningLesson = learningLessonService.lambdaQuery()
                .eq(LearningLesson::getId,formDTO.getLessonId())
                .eq(LearningLesson::getUserId,userId)
                .one();
        if(learningLesson == null){
            throw new BizIllegalException("课程不存在，无法更新数据");
        }
        // 判断是否有新的完成小节
        boolean isAll = false; //判断课程是否全部学完
        if(isFinished){
            //如果第一次完成，判断课程是否全部学完
            Integer learnedSections = learningLesson.getLearnedSections();//获取已经学习的小节数量
            CourseFullInfoDTO courseInfoById = courseClient.getCourseInfoById(learningLesson.getCourseId(), false, false);
            if(courseInfoById == null){
                throw new BizIllegalException("课程不存在，无法更新数据");
            }
            Integer sectionNum = courseInfoById.getSectionNum();//获取课程的总小节数量
            isAll = learnedSections + 1 >= sectionNum;
            //如果第一次学完，积分增加10
            mqHelper.send(
                    LEARNING_EXCHANGE,
                    LEARN_SECTION,
                    SignInMessage.of(userId,10)
            );
        }
        //如果不是第一次完成，需要更新数据
        learningLessonService.lambdaUpdate()
                .set(LearningLesson::getLatestSectionId,formDTO.getSectionId())
                .set(LearningLesson::getLatestLearnTime, LocalDateTime.now())
                .set(learningLesson.getStatus() == LessonStatus.NOT_BEGIN,LearningLesson::getStatus,LessonStatus.LEARNING)
                .set(isAll,LearningLesson::getStatus, LessonStatus.FINISHED)
                .setSql(isFinished,"learned_sections = learned_sections + 1")
                .eq(LearningLesson::getId,learningLesson.getId())
                .update();
    }

    private boolean handleExamRecord(Long userId, LearningRecordFormDTO formDTO) {
        LearningRecord record = lambdaQuery()
                .eq(LearningRecord::getSectionId, formDTO.getSectionId())
                .one();
        if(record != null){
            //代表已经有该记录，不是第一次学
            return false;
        }
        LearningRecord learningRecord = BeanUtil.toBean(formDTO, LearningRecord.class);
        learningRecord.setUserId(userId);
        learningRecord.setFinished(true);
        learningRecord.setFinishTime(formDTO.getCommitTime());
        boolean success = save(learningRecord);
        if(!success){
            throw new DbException("新增考试记录失败");
        }
        return true;
    }

    private boolean handleVideoRecord(Long userId, LearningRecordFormDTO formDTO) {
        LearningRecord record = lambdaQuery()
                .eq(LearningRecord::getSectionId, formDTO.getSectionId())
                .eq(LearningRecord::getLessonId,formDTO.getLessonId())
                .one();
        //判断是否完成该小节视频
        boolean isFinished;
        if(record != null){
            //代表已经有该记录，不是第一次学
            isFinished = !record.getFinished() && formDTO.getDuration() <= formDTO.getMoment() * 2;
            if(!isFinished){
                //如果不是第一次学完
                LearningRecord learningRecord = new LearningRecord();
                learningRecord.setMoment(formDTO.getMoment());
                learningRecord.setId(record.getId());
                learningRecord.setFinished(record.getFinished());
                learningRecord.setSectionId(formDTO.getSectionId());
                learningRecord.setLessonId(formDTO.getLessonId());

                //添加缓存并且提交延迟队列
                recordDelayTaskHandler.addLearningRecordTask(learningRecord);
                return false;
            }
            //更新学习记录
            boolean success = lambdaUpdate()
                    .set(LearningRecord::getMoment, formDTO.getMoment())
                    .set(LearningRecord::getFinished, true)
                    .set(LearningRecord::getFinishTime, formDTO.getCommitTime())
                    .eq(LearningRecord::getId, record.getId())
                    .update();
            if(!success){
                throw new DbException("更新学习记录失败");
            }
            //因为到这一步说明是第一次学完，清理redis缓存,保证数据一致性
            recordDelayTaskHandler.cleanRecordCache(formDTO.getLessonId(),formDTO.getSectionId());
            return true;
        }
        //没有学习记录，为第一次学，则新增学习记录
        LearningRecord learningRecord = BeanUtil.toBean(formDTO, LearningRecord.class);
        learningRecord.setUserId(userId);
        boolean save = save(learningRecord);
        if(!save){
            throw new DbException("新增学习记录失败");
        }
        return false;
    }
}
